home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / term43-source.lha / Extras / Source / term-Source.lha / termFileBuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-07  |  22.0 KB  |  1,158 lines

  1. /*
  2. **    termFileBuffer.c
  3. **
  4. **    Double-buffered file I/O routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termGlobal.h"
  11.  
  12.     /* Argument types. */
  13.  
  14. enum    {    ARG_NAME,ARG_MODE };
  15. enum    {    ARG_OFFSET,ARG_ORIGIN };
  16.  
  17.     /* Seek offsets. */
  18.  
  19. enum    {    SEEKFILE_SET,SEEKFILE_CURR,SEEKFILE_END };
  20.  
  21.     /* Command codes. */
  22.  
  23. enum    {    BUF_CLOSE,BUF_SEEK,BUF_FILL,BUF_FLUSH };
  24.  
  25.     /* ObtainInfo(struct Buffer *File):
  26.      *
  27.      *    Obtain information on the disk a buffered file
  28.      *    resides on.
  29.      */
  30.  
  31. STATIC VOID __regargs
  32. ObtainInfo(struct Buffer *File)
  33. {
  34.         /* Lock on the path available? */
  35.  
  36.     if(File -> DirLock)
  37.     {
  38.             /* Obtain information... */
  39.  
  40.         if(!Info(File -> DirLock,&File -> InfoData))
  41.         {
  42.                 /* No success, release resources. */
  43.  
  44.             UnLock(File -> DirLock);
  45.  
  46.             File -> DirLock = NULL;
  47.  
  48.             File -> InfoData . id_NumBlocks        = 0;
  49.             File -> InfoData . id_BytesPerBlock    = 0;
  50.         }
  51.     }
  52. }
  53.  
  54.     /* FileBufferServer():
  55.      *
  56.      *    Background process to handle the buffering
  57.      *    of a filehandle, automatically gets invoked
  58.      *    when a file is opened.
  59.      */
  60.  
  61. STATIC VOID __saveds
  62. FileBufferServer(VOID)
  63. {
  64.     struct MsgPort    *Port;
  65.     struct Buffer    *Buffer;
  66.     BYTE         Terminated = FALSE,
  67.              Done,
  68.              WasFull;
  69.     UBYTE        *String;
  70.     APTR         Data;
  71.     LONG         Length;
  72.     BPTR         SomeLock;
  73.  
  74.         /* Wait for startup message (-> Buffer). */
  75.  
  76.     Port = &((struct Process *)SysBase -> ThisTask) -> pr_MsgPort;
  77.  
  78.     WaitPort(Port);
  79.  
  80.     Buffer = (struct Buffer *)GetMsg(Port);
  81.  
  82.         /* Open the file and obtain a filehandle. */
  83.  
  84.     String = (STRPTR)Buffer -> ActionData[ARG_MODE];
  85.  
  86.     Buffer -> WriteAccess = TRUE;
  87.  
  88.         /* Put the message into the list. */
  89.  
  90.     ObtainSemaphore(&DoubleBufferSemaphore);
  91.  
  92.     AddTail(&DoubleBufferList,(struct Node *)Buffer);
  93.  
  94.     ReleaseSemaphore(&DoubleBufferSemaphore);
  95.  
  96.         /* Remember the opening date. */
  97.  
  98.     DateStamp(&Buffer -> OpenDate);
  99.  
  100.         /* Check for the open type. */
  101.  
  102.     switch(String[0])
  103.     {
  104.         case 'r':
  105.  
  106.             if(String[1] == '+')
  107.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  108.             else
  109.             {
  110.                 Buffer -> WriteAccess = FALSE;
  111.  
  112.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_OLDFILE);
  113.             }
  114.  
  115.             break;
  116.  
  117.         case 'w':
  118.  
  119.             if(String[1] == '+')
  120.             {
  121.                 if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  122.                 {
  123.                     UnLock(SomeLock);
  124.  
  125.                     DeleteFile((STRPTR)Buffer -> ActionData[ARG_NAME]);
  126.                 }
  127.  
  128.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE);
  129.             }
  130.             else
  131.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  132.  
  133.             break;
  134.  
  135.         case 'a':
  136.  
  137.             if(SomeLock = Lock((STRPTR)Buffer -> ActionData[ARG_NAME],ACCESS_WRITE))
  138.             {
  139.                 UnLock(SomeLock);
  140.  
  141.                 if(Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_READWRITE))
  142.                 {
  143.                     if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  144.                     {
  145.                         Close(Buffer -> FileHandle);
  146.  
  147.                         Buffer -> FileHandle = NULL;
  148.                     }
  149.                 }
  150.             }
  151.             else
  152.                 Buffer -> FileHandle = Open((STRPTR)Buffer -> ActionData[ARG_NAME],MODE_NEWFILE);
  153.  
  154.             break;
  155.     }
  156.  
  157.         /* Clear signal bit. */
  158.  
  159.     ClrSignal(SIG_COMMAND);
  160.  
  161.         /* Did the file open? */
  162.  
  163.     if(Buffer -> FileHandle)
  164.     {
  165.         Buffer -> Data        = Buffer -> DataBuffer[0];
  166.         Buffer -> DataCount    = 1;
  167.         Buffer -> Fresh        = TRUE;
  168.  
  169.             /* If not in write mode fill the buffers. */
  170.  
  171.         if(!Buffer -> WriteAccess)
  172.         {
  173.                 /* Fill the first one synchronously. */
  174.  
  175.             Buffer -> ReadBufFull    = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  176.             Buffer -> Read        = TRUE;
  177.             Buffer -> RealPosition    = Buffer -> ReadBufFull;
  178.  
  179.                 /* Restart caller. */
  180.  
  181.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  182.  
  183.                 /* Fill the second buffe asynchronously. */
  184.  
  185.             Buffer -> DataLength[1]    = Buffer -> Cached = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  186.             Buffer -> RealPosition += Buffer -> Cached;
  187.         }
  188.         else
  189.         {
  190.             UBYTE     TempBuffer[MAX_FILENAME_LENGTH],
  191.                 *Stop;
  192.             BPTR     TempLock;
  193.  
  194.             strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  195.  
  196.             Stop = PathPart(TempBuffer);
  197.  
  198.             *Stop = 0;
  199.  
  200.             if(TempLock = Lock(TempBuffer,ACCESS_READ))
  201.             {
  202.                 BPTR OldDir = CurrentDir(TempLock);
  203.  
  204.                 Buffer -> DirLock = Lock(":",ACCESS_READ);
  205.  
  206.                 CurrentDir(OldDir);
  207.  
  208.                 UnLock(TempLock);
  209.             }
  210.  
  211.             ObtainInfo(Buffer);
  212.  
  213.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  214.         }
  215.     }
  216.     else
  217.         Terminated = TRUE;
  218.  
  219.         /* Go into loop waiting for commands. */
  220.  
  221.     while(!Terminated)
  222.     {
  223.         Wait(SIG_COMMAND);
  224.  
  225.         Done = FALSE;
  226.  
  227.         Buffer -> Result = 0;
  228.  
  229.             /* Take care of each action. */
  230.  
  231.         switch(Buffer -> Action)
  232.         {
  233.                 /* Close the file, flush any dirty
  234.                  * buffers and exit.
  235.                  */
  236.  
  237.             case BUF_CLOSE:
  238.  
  239.                 Buffer -> Result = TRUE;
  240.  
  241.                 if(Buffer -> BufPosition && Buffer -> Written)
  242.                 {
  243.                     if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  244.                         Buffer -> Result = FALSE;
  245.                 }
  246.  
  247.                 if(!Close(Buffer -> FileHandle))
  248.                     Buffer -> Result = FALSE;
  249.  
  250.                 if(Buffer -> DirLock)
  251.                     UnLock(Buffer -> DirLock);
  252.  
  253.                 Terminated = TRUE;
  254.  
  255.                 break;
  256.  
  257.                 /* Seek to a specific file position. */
  258.  
  259.             case BUF_SEEK:
  260.  
  261.                 Buffer -> Result = 0;
  262.  
  263.                     /* Do nothing if buffer is still
  264.                      * untouched and we are required
  265.                      * to seek back to the beginning
  266.                      * of the file.
  267.                      */
  268.  
  269.                 if(Buffer -> Fresh && !Buffer -> ActionData[ARG_OFFSET] && Buffer -> ActionData[ARG_ORIGIN] == SEEKFILE_SET)
  270.                 {
  271.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  272.  
  273.                     Done = TRUE;
  274.                 }
  275.                 else
  276.                 {
  277.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  278.                     Buffer -> Read        = FALSE;
  279.  
  280.                     if(Buffer -> BufPosition && Buffer -> Written)
  281.                     {
  282.                         if(Write(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufPosition) != Buffer -> BufPosition)
  283.                             Buffer -> Result = -1;
  284.                         else
  285.                             ObtainInfo(Buffer);
  286.                     }
  287.  
  288.                     if(!Buffer -> Result)
  289.                     {
  290.                         Buffer -> Result = Buffer -> RealPosition - (Buffer -> ReadBufFull + Buffer -> Cached);
  291.  
  292.                         switch(Buffer -> ActionData[ARG_ORIGIN])
  293.                         {
  294.                             case SEEKFILE_SET:
  295.  
  296.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_BEGINNING) != -1)
  297.                                     Buffer -> RealPosition = Buffer -> ActionData[ARG_OFFSET];
  298.                                 else
  299.                                     Buffer -> Result = -1;
  300.  
  301.                                 break;
  302.  
  303.                             case SEEKFILE_CURR:
  304.  
  305.                                 if(!Buffer -> WriteAccess && Buffer -> ActionData[ARG_OFFSET] >= 0 && Buffer -> ReadBufFull - Buffer -> ActionData[ARG_OFFSET] >= 0)
  306.                                 {
  307.                                     Buffer -> ReadBufFull    -= Buffer -> ActionData[ARG_OFFSET];
  308.                                     Buffer -> Data        += Buffer -> ActionData[ARG_OFFSET];
  309.  
  310.                                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  311.  
  312.                                     Done = TRUE;
  313.  
  314.                                     break;
  315.                                 }
  316.  
  317.                                 if(Seek(Buffer -> FileHandle,-(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET],OFFSET_CURRENT) != -1)
  318.                                     Buffer -> RealPosition += -(Buffer -> ReadBufFull + Buffer -> Cached) + Buffer -> ActionData[ARG_OFFSET];
  319.                                 else
  320.                                     Buffer -> Result = -1;
  321.  
  322.                                 break;
  323.  
  324.                             case SEEKFILE_END:
  325.  
  326.                                 if(Seek(Buffer -> FileHandle,Buffer -> ActionData[ARG_OFFSET],OFFSET_END) != -1)
  327.                                     Buffer -> RealPosition = Seek(Buffer -> FileHandle,0,OFFSET_CURRENT);
  328.                                 else
  329.                                     Buffer -> Result = -1;
  330.  
  331.                                 break;
  332.  
  333.                             default:
  334.  
  335.                                 Buffer -> Result = -1;
  336.                         }
  337.  
  338.                         Buffer -> ReadBufFull = 0;
  339.  
  340.                         if(Buffer -> Result != -1)
  341.                         {
  342.                             Buffer -> Data        = Buffer -> DataBuffer[0];
  343.                             Buffer -> DataCount    = 1;
  344.  
  345.                             if(!Buffer -> WriteAccess)
  346.                             {
  347.                                 Buffer -> ReadBufFull     = Read(Buffer -> FileHandle,Buffer -> Data,Buffer -> BufLength);
  348.                                 Buffer -> WriteBufFull     = 0;
  349.                                 Buffer -> Read         = TRUE;
  350.                                 Buffer -> RealPosition    += Buffer -> ReadBufFull;
  351.  
  352.                                 if(Buffer -> ReadBufFull)
  353.                                 {
  354.                                     Buffer -> Cached = Buffer -> DataLength[1] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[1],Buffer -> BufLength);
  355.  
  356.                                     Buffer -> RealPosition += Buffer -> Cached;
  357.                                 }
  358.                             }
  359.                         }
  360.                         else
  361.                             Buffer -> LastActionFailed = TRUE;
  362.                     }
  363.                     else
  364.                         Buffer -> ReadBufFull = 0;
  365.  
  366.                     Buffer -> BufPosition    = 0;
  367.                     Buffer -> Written    = FALSE;
  368.                 }
  369.  
  370.                 break;
  371.  
  372.                 /* Fill the buffer with fresh data. */
  373.  
  374.             case BUF_FILL:
  375.  
  376.                 Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  377.                 Buffer -> ReadBufFull    = Buffer -> DataLength[Buffer -> DataCount];
  378.                 Buffer -> WriteBufFull    = 0;
  379.                 Buffer -> BufPosition    = 0;
  380.                 Buffer -> Read        = TRUE;
  381.                 Buffer -> Written    = FALSE;
  382.                 Buffer -> Fresh        = FALSE;
  383.  
  384.                 if(Buffer -> ReadBufFull)
  385.                     WasFull = TRUE;
  386.                 else
  387.                     WasFull = FALSE;
  388.  
  389.                     /* The buffer contents have been
  390.                      * swapped, now wake the caller
  391.                      * up and fill the next buffer
  392.                      * asynchronously.
  393.                      */
  394.  
  395.                 Signal(Buffer -> Caller,SIG_HANDSHAKE);
  396.  
  397.                 Done = TRUE;
  398.  
  399.                 if(WasFull)
  400.                 {
  401.                     Buffer -> DataCount = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  402.  
  403.                     Buffer -> Cached = Buffer -> DataLength[Buffer -> DataCount] = Read(Buffer -> FileHandle,Buffer -> DataBuffer[Buffer -> DataCount],Buffer -> BufLength);
  404.  
  405.                     Buffer -> RealPosition += Buffer -> Cached;
  406.  
  407.                     if(!Buffer -> DataLength[Buffer -> DataCount])
  408.                     {
  409.                         if(IoErr())
  410.                             Buffer -> LastActionFailed = TRUE;
  411.                     }
  412.                 }
  413.  
  414.                 break;
  415.  
  416.                 /* Flush the contents of the buffer to disk. */
  417.  
  418.             case BUF_FLUSH:
  419.  
  420.                 if(Buffer -> BufPosition && Buffer -> Written)
  421.                 {
  422.                     Data            = Buffer -> Data;
  423.                     Length            = Buffer -> BufPosition;
  424.  
  425.                     Buffer -> Data        = Buffer -> DataBuffer[Buffer -> DataCount];
  426.                     Buffer -> DataCount    = (Buffer -> DataCount + 1) % BUFFER_NUMBER;
  427.  
  428.                     Buffer -> ReadBufFull    = 0;
  429.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  430.                     Buffer -> BufPosition    = 0;
  431.                     Buffer -> Read        = FALSE;
  432.                     Buffer -> Written    = FALSE;
  433.  
  434.                     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  435.  
  436.                     Done = TRUE;
  437.  
  438.                     if(Write(Buffer -> FileHandle,Data,Length) != Length)
  439.                         Buffer -> LastActionFailed = TRUE;
  440.                     else
  441.                     {
  442.                         ObtainInfo(Buffer);
  443.  
  444.                         Buffer -> RealPosition += Length;
  445.                     }
  446.                 }
  447.                 else
  448.                 {
  449.                     Buffer -> ReadBufFull    = 0;
  450.                     Buffer -> WriteBufFull    = Buffer -> BufLength;
  451.                     Buffer -> BufPosition    = 0;
  452.                     Buffer -> Read        = FALSE;
  453.                     Buffer -> Written    = FALSE;
  454.                 }
  455.  
  456.                 Buffer -> Fresh = FALSE;
  457.  
  458.                 break;
  459.         }
  460.  
  461.             /* Ring back if necessary. */
  462.  
  463.         if(!Done && !Terminated)
  464.             Signal(Buffer -> Caller,SIG_HANDSHAKE);
  465.     }
  466.  
  467.         /* Remove the message from the list. */
  468.  
  469.     ObtainSemaphore(&DoubleBufferSemaphore);
  470.  
  471.     Remove((struct Node *)Buffer);
  472.  
  473.     ReleaseSemaphore(&DoubleBufferSemaphore);
  474.  
  475.         /* Lock & quit. */
  476.  
  477.     Forbid();
  478.  
  479.     Signal(Buffer -> Caller,SIG_HANDSHAKE);
  480. }
  481.  
  482.     /* BufferFill(struct Buffer *Buffer):
  483.      *
  484.      *    Fills a given buffer with fresh data.
  485.      */
  486.  
  487. STATIC BYTE __inline
  488. BufferFill(struct Buffer *Buffer)
  489. {
  490.     if(Buffer -> LastActionFailed)
  491.         return(FALSE);
  492.     else
  493.     {
  494.         if(!Buffer -> ReadBufFull)
  495.         {
  496.             Buffer -> Action = BUF_FILL;
  497.  
  498.             Forbid();
  499.  
  500.             Signal(Buffer -> Child,SIG_COMMAND);
  501.  
  502.             ClrSignal(SIG_HANDSHAKE);
  503.  
  504.             Wait(SIG_HANDSHAKE);
  505.  
  506.             Permit();
  507.         }
  508.  
  509.         return(TRUE);
  510.     }
  511. }
  512.  
  513.     /* IsValidBuffer(struct Buffer *Buffer):
  514.      *
  515.      *    Scans the double buffered file list for
  516.      *    a valid entry.
  517.      */
  518.  
  519. STATIC BYTE __inline
  520. IsValidBuffer(struct Buffer *Buffer)
  521. {
  522.     BYTE         GotIt = FALSE;
  523.     struct Node    *Node;
  524.  
  525.     ObtainSemaphore(&DoubleBufferSemaphore);
  526.  
  527.     Node = DoubleBufferList . lh_Head;
  528.  
  529.     while(Node -> ln_Succ)
  530.     {
  531.         if(Buffer == (struct Buffer *)Node)
  532.         {
  533.             GotIt = TRUE;
  534.  
  535.             break;
  536.         }
  537.  
  538.         Node = Node -> ln_Succ;
  539.     }
  540.  
  541.     ReleaseSemaphore(&DoubleBufferSemaphore);
  542.  
  543.     return(GotIt);
  544. }
  545.  
  546.     /* OpenFileSimple(STRPTR Name,STRPTR AccessMode):
  547.      *
  548.      *    Open simple (unbuffered) file.
  549.      */
  550.  
  551. STATIC struct Buffer * __regargs
  552. OpenFileSimple(STRPTR Name,STRPTR AccessMode)
  553. {
  554.     struct Buffer *Buffer;
  555.  
  556.         /* Allocate buffer handle (dummy). */
  557.  
  558.     if(Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer),MEMF_ANY | MEMF_CLEAR))
  559.     {
  560.         BPTR SomeLock;
  561.  
  562.             /* Provide basic information. */
  563.  
  564.         DateStamp(&Buffer -> OpenDate);
  565.  
  566.         Buffer -> WriteAccess = TRUE;
  567.  
  568.         Buffer -> SimpleIO = TRUE;
  569.  
  570.             /* Open the file. */
  571.  
  572.         switch(AccessMode[0])
  573.         {
  574.             case 'r':
  575.  
  576.                 if(AccessMode[1] == '+')
  577.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  578.                 else
  579.                 {
  580.                     Buffer -> WriteAccess = FALSE;
  581.  
  582.                     Buffer -> FileHandle = Open(Name,MODE_OLDFILE);
  583.                 }
  584.  
  585.                 break;
  586.  
  587.             case 'w':
  588.  
  589.                 if(AccessMode[1] == '+')
  590.                 {
  591.                     if(SomeLock = Lock(Name,ACCESS_WRITE))
  592.                     {
  593.                         UnLock(SomeLock);
  594.  
  595.                         DeleteFile(Name);
  596.                     }
  597.  
  598.                     Buffer -> FileHandle = Open(Name,MODE_READWRITE);
  599.                 }
  600.                 else
  601.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  602.  
  603.                 break;
  604.  
  605.             case 'a':
  606.  
  607.                 if(SomeLock = Lock(Name,ACCESS_WRITE))
  608.                 {
  609.                     UnLock(SomeLock);
  610.  
  611.                     if(Buffer -> FileHandle = Open(Name,MODE_READWRITE))
  612.                     {
  613.                         if(Seek(Buffer -> FileHandle,0,OFFSET_END) == -1)
  614.                         {
  615.                             Close(Buffer -> FileHandle);
  616.  
  617.                             Buffer -> FileHandle = NULL;
  618.                         }
  619.                     }
  620.                 }
  621.                 else
  622.                     Buffer -> FileHandle = Open(Name,MODE_NEWFILE);
  623.  
  624.                 break;
  625.         }
  626.  
  627.             /* Did we succeed in opening the file? */
  628.  
  629.         if(Buffer -> FileHandle)
  630.         {
  631.                 /* Try to obtain a lock on the destination directory. */
  632.  
  633.             if(Buffer -> WriteAccess)
  634.             {
  635.                 UBYTE     TempBuffer[MAX_FILENAME_LENGTH],
  636.                     *Stop;
  637.                 BPTR     TempLock;
  638.  
  639.                 strcpy(TempBuffer,(STRPTR)Buffer -> ActionData[ARG_NAME]);
  640.  
  641.                 Stop = PathPart(TempBuffer);
  642.  
  643.                 *Stop = 0;
  644.  
  645.                 if(TempLock = Lock(TempBuffer,ACCESS_READ))
  646.                 {
  647.                     BPTR OldDir = CurrentDir(TempLock);
  648.  
  649.                     Buffer -> DirLock = Lock(":",ACCESS_READ);
  650.  
  651.                     CurrentDir(OldDir);
  652.  
  653.                     UnLock(TempLock);
  654.                 }
  655.  
  656.                 ObtainInfo(Buffer);
  657.             }
  658.  
  659.                 /* Link the file into the list. */
  660.  
  661.             ObtainSemaphore(&DoubleBufferSemaphore);
  662.  
  663.             AddTail(&DoubleBufferList,(struct Node *)Buffer);
  664.  
  665.             ReleaseSemaphore(&DoubleBufferSemaphore);
  666.  
  667.             return(Buffer);
  668.         }
  669.         else
  670.             FreeVecPooled(Buffer);
  671.     }
  672.  
  673.     return(NULL);
  674. }
  675.  
  676.     /* OpenFileBuffered(STRPTR Name,STRPTR AccessMode):
  677.      *
  678.      *    Open double-buffered file.
  679.      */
  680.  
  681. STATIC struct Buffer * __regargs
  682. OpenFileBuffered(STRPTR Name,STRPTR AccessMode)
  683. {
  684.     struct Buffer    *Buffer;
  685.     LONG         Size;
  686.  
  687.     Size = Config -> MiscConfig -> IOBufferSize;
  688.  
  689.         /* Allocate the buffer data. */
  690.  
  691.     do
  692.     {
  693.         Buffer = (struct Buffer *)AllocVecPooled(sizeof(struct Buffer) + (Size + 15) * BUFFER_NUMBER,MEMF_ANY | MEMF_CLEAR);
  694.  
  695.         Size /= 2;
  696.     }
  697.     while(!Buffer && Size > 2048);
  698.  
  699.     if(Buffer)
  700.     {
  701.         struct Process    *Process;
  702.         WORD         i;
  703.  
  704.             /* Set up the first buffer. */
  705.  
  706.         Buffer -> DataBuffer[0] = (STRPTR)(Buffer + 1);
  707.  
  708.             /* Set up the individual buffers. */
  709.  
  710.         for(i = 1 ; i < BUFFER_NUMBER ; i++)
  711.             Buffer -> DataBuffer[i] = Buffer -> DataBuffer[i - 1] + Size + 15;
  712.  
  713.             /* Do the quad-longword alignment. */
  714.  
  715.         for(i = 0 ; i < BUFFER_NUMBER ; i++)
  716.             Buffer -> DataBuffer[i] = (UBYTE *)(((ULONG)Buffer -> DataBuffer[i] + 15) & ~15);
  717.  
  718.         Buffer -> BufLength    = Size;
  719.         Buffer -> WriteBufFull    = Buffer -> BufLength;
  720.  
  721.             /* Create the asynchronous file server. */
  722.  
  723.         if(!(Process = CreateNewProcTags(
  724.             NP_Entry,    FileBufferServer,
  725.             NP_Name,    "term File Process",
  726.             NP_Priority,    SysBase -> ThisTask -> tc_Node . ln_Pri,
  727.             NP_StackSize,    8192,
  728.             NP_WindowPtr,    -1,
  729.         TAG_DONE)))
  730.         {
  731.             FreeVecPooled(Buffer);
  732.  
  733.             return(NULL);
  734.         }
  735.  
  736.             /* Set up the message header. */
  737.  
  738.         Buffer -> Message . mn_Length    = sizeof(struct Buffer);
  739.  
  740.         Buffer -> ActionData[ARG_NAME]    = (LONG)Name;
  741.         Buffer -> ActionData[ARG_MODE]    = (LONG)AccessMode;
  742.  
  743.         Buffer -> Child            = Process;
  744.         Buffer -> Caller        = (struct Process *)SysBase -> ThisTask;
  745.  
  746.         Forbid();
  747.  
  748.             /* Send it to the waiting server process. */
  749.  
  750.         PutMsg(&Process -> pr_MsgPort,&Buffer -> Message);
  751.  
  752.             /* Wait for ringback. */
  753.  
  754.         ClrSignal(SIG_HANDSHAKE);
  755.  
  756.         Wait(SIG_HANDSHAKE);
  757.  
  758.         Permit();
  759.  
  760.             /* Do we have a valid filehandle? */
  761.  
  762.         if(!Buffer -> FileHandle)
  763.         {
  764.             FreeVecPooled(Buffer);
  765.  
  766.             return(NULL);
  767.         }
  768.         else
  769.             return(Buffer);
  770.     }
  771.  
  772.     return(NULL);
  773. }
  774.  
  775.     /* BPrintf():
  776.      *
  777.      *    Prints text into a buffered file.
  778.      */
  779.  
  780. LONG __stdargs
  781. BPrintf(struct Buffer *Buffer,STRPTR Format,...)
  782. {
  783.     UBYTE    String[256];
  784.     va_list    VarArgs;
  785.  
  786.     va_start(VarArgs,Format);
  787.     VSPrintf(String,Format,VarArgs);
  788.     va_end(VarArgs);
  789.  
  790.     return(BufferWrite(Buffer,String,strlen(String)));
  791. }
  792.  
  793.     /* BufferFlush(struct Buffer *Buffer):
  794.      *
  795.      *    Flush the contents of a given buffer to disk.
  796.      */
  797.  
  798. BYTE __regargs
  799. BufferFlush(struct Buffer *Buffer)
  800. {
  801.     if(Buffer -> LastActionFailed)
  802.         return(FALSE);
  803.     else
  804.     {
  805.         if(Buffer -> BufPosition && Buffer -> Written)
  806.         {
  807.             Buffer -> Action = BUF_FLUSH;
  808.  
  809.             Forbid();
  810.  
  811.             Signal(Buffer -> Child,SIG_COMMAND);
  812.  
  813.             ClrSignal(SIG_HANDSHAKE);
  814.  
  815.             Wait(SIG_HANDSHAKE);
  816.  
  817.             Permit();
  818.         }
  819.  
  820.         return(TRUE);
  821.     }
  822. }
  823.  
  824.     /* BufferClose(struct Buffer *Buffer):
  825.      *
  826.      *    Close a buffered filehandle.
  827.      */
  828.  
  829. BYTE __regargs
  830. BufferClose(struct Buffer *Buffer)
  831. {
  832.     if(IsValidBuffer(Buffer))
  833.     {
  834.         BYTE Success;
  835.  
  836.             /* Unbuffered file handle? */
  837.  
  838.         if(Buffer -> SimpleIO)
  839.         {
  840.                 /* Drop the destination drawer lock. */
  841.  
  842.             if(Buffer -> DirLock)
  843.                 UnLock(Buffer -> DirLock);
  844.  
  845.                 /* Close the file. */
  846.  
  847.             if(Close(Buffer -> FileHandle))
  848.                 Success = TRUE;
  849.             else
  850.                 Success = FALSE;
  851.  
  852.                 /* Unlink the handle. */
  853.  
  854.             ObtainSemaphore(&DoubleBufferSemaphore);
  855.  
  856.             Remove((struct Node *)Buffer);
  857.  
  858.             ReleaseSemaphore(&DoubleBufferSemaphore);
  859.         }
  860.         else
  861.         {
  862.             Buffer -> Action = BUF_CLOSE;
  863.  
  864.             Forbid();
  865.  
  866.             Signal(Buffer -> Child,SIG_COMMAND);
  867.  
  868.             ClrSignal(SIG_HANDSHAKE);
  869.  
  870.             Wait(SIG_HANDSHAKE);
  871.  
  872.             Permit();
  873.  
  874.             Success = Buffer -> Result;
  875.         }
  876.  
  877.         FreeVecPooled(Buffer);
  878.  
  879.         return(Success);
  880.     }
  881.     else
  882.         return(FALSE);
  883. }
  884.  
  885.     /* BufferOpen(STRPTR Name,STRPTR AccessMode):
  886.      *
  887.      *    Open a file for buffered I/O.
  888.      */
  889.  
  890. struct Buffer * __regargs
  891. BufferOpen(STRPTR Name,STRPTR AccessMode)
  892. {
  893.         /* Simple file handling? */
  894.  
  895.     if(Config -> MiscConfig -> SimpleIO)
  896.         return(OpenFileSimple(Name,AccessMode));
  897.     else
  898.     {
  899.         struct Buffer *Buffer;
  900.  
  901.             /* Try to open a buffered file, if unsuccessful
  902.              * fall back to simple file I/O.
  903.              */
  904.  
  905.         if(!(Buffer = OpenFileBuffered(Name,AccessMode)))
  906.             Buffer = OpenFileSimple(Name,AccessMode);
  907.  
  908.         return(Buffer);
  909.     }
  910. }
  911.  
  912.     /* BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin):
  913.      *
  914.      *    Move the read/write pointer to a specific position
  915.      *    in a file (not really buffered).
  916.      */
  917.  
  918. BYTE __regargs
  919. BufferSeek(struct Buffer *Buffer,LONG Offset,LONG Origin)
  920. {
  921.     if(Buffer -> SimpleIO)
  922.     {
  923.         if(Seek(Buffer -> FileHandle,Offset,Origin) == -1)
  924.             return(FALSE);
  925.         else
  926.             return(TRUE);
  927.     }
  928.     else
  929.     {
  930.         Buffer -> Action            = BUF_SEEK;
  931.         Buffer -> ActionData[ARG_OFFSET]    = Offset;
  932.         Buffer -> ActionData[ARG_ORIGIN]    = Origin;
  933.  
  934.         Forbid();
  935.  
  936.         Signal(Buffer -> Child,SIG_COMMAND);
  937.  
  938.         ClrSignal(SIG_HANDSHAKE);
  939.  
  940.         Wait(SIG_HANDSHAKE);
  941.  
  942.         Permit();
  943.  
  944.         if(Buffer -> Result == -1)
  945.             return(FALSE);
  946.         else
  947.             return(TRUE);
  948.     }
  949. }
  950.  
  951.     /* BufferRead():
  952.      *
  953.      *    Read data from a file (buffered).
  954.      */
  955.  
  956. LONG __regargs
  957. BufferRead(struct Buffer *Buffer,STRPTR Destination,LONG Size)
  958. {
  959.     if(Buffer -> SimpleIO)
  960.     {
  961.         LONG Bytes;
  962.  
  963.         Buffer -> Used = TRUE;
  964.  
  965.         if((Bytes = Read(Buffer -> FileHandle,Destination,Size)) < 0)
  966.             Bytes = 0;
  967.  
  968.         return(Bytes);
  969.     }
  970.     else
  971.     {
  972.         LONG     BytesRead = 0,ToCopy,BufPosition,ReadBufFull;
  973.         UBYTE    *Data;
  974.  
  975.             /* If there is still data to be written in
  976.              * the buffer, write it.
  977.              */
  978.  
  979.         if(Buffer -> Written)
  980.         {
  981.             if(!BufferFlush(Buffer))
  982.                 return(0);
  983.         }
  984.  
  985.             /* Set up for read access. */
  986.  
  987.         BufPosition    = Buffer -> BufPosition;
  988.         ReadBufFull    = Buffer -> ReadBufFull;
  989.         Data        = &Buffer -> Data[BufPosition];
  990.  
  991.             /* Remember access. */
  992.  
  993.         Buffer -> Used    = TRUE;
  994.  
  995.             /* Continue until all data has been processed. */
  996.  
  997.         while(Size)
  998.         {
  999.                 /* Determine number of bytes to transfer. */
  1000.  
  1001.             if(ToCopy = (Size > ReadBufFull) ? ReadBufFull : Size)
  1002.             {
  1003.                 CopyMem(Data,Destination,ToCopy);
  1004.  
  1005.                 Size        -= ToCopy;
  1006.                 BufPosition    += ToCopy;
  1007.                 ReadBufFull    -= ToCopy;
  1008.                 Destination    += ToCopy;
  1009.                 Data        += ToCopy;
  1010.                 BytesRead    += ToCopy;
  1011.             }
  1012.             else
  1013.             {
  1014.                     /* Refill buffer with data. */
  1015.  
  1016.                 Buffer -> BufPosition    = BufPosition;
  1017.                 Buffer -> ReadBufFull    = ReadBufFull;
  1018.  
  1019.                 if(!BufferFill(Buffer))
  1020.                     return(BytesRead);
  1021.  
  1022.                 if(!Buffer -> ReadBufFull)
  1023.                 {
  1024.                     Buffer -> BufPosition = BufPosition;
  1025.  
  1026.                     return(BytesRead);
  1027.                 }
  1028.  
  1029.                     /* Pick up new data. */
  1030.  
  1031.                 BufPosition        = Buffer -> BufPosition;
  1032.                 ReadBufFull        = Buffer -> ReadBufFull;
  1033.                 Data            = Buffer -> Data;
  1034.             }
  1035.         }
  1036.  
  1037.             /* Install new data. */
  1038.  
  1039.         Buffer -> BufPosition    = BufPosition;
  1040.         Buffer -> ReadBufFull    = ReadBufFull;
  1041.  
  1042.         return(BytesRead);
  1043.     }
  1044. }
  1045.  
  1046.     /* BufferWrite():
  1047.      *
  1048.      *    Write data to a file (buffered).
  1049.      */
  1050.  
  1051. LONG __regargs
  1052. BufferWrite(struct Buffer *Buffer,STRPTR Source,LONG Size)
  1053. {
  1054.     if(Buffer -> SimpleIO)
  1055.     {
  1056.         LONG Bytes;
  1057.  
  1058.         Buffer -> Used = TRUE;
  1059.  
  1060.         Buffer -> WriteAccess = TRUE;
  1061.  
  1062.         if((Bytes = Write(Buffer -> FileHandle,Source,Size)) < 0)
  1063.             Bytes = 0;
  1064.         else
  1065.         {
  1066.             Buffer -> BufPosition += Bytes;
  1067.  
  1068.             if(Buffer -> BufPosition >= Config -> MiscConfig -> IOBufferSize)
  1069.             {
  1070.                 Buffer -> BufPosition = 0;
  1071.  
  1072.                 ObtainInfo(Buffer);
  1073.             }
  1074.         }
  1075.  
  1076.         return(Bytes);
  1077.     }
  1078.     else
  1079.     {
  1080.         LONG     BytesWritten = 0,ToCopy,BufPosition,WriteBufFull;
  1081.         UBYTE    *Data;
  1082.  
  1083.             /* If there is still read data in the buffer,
  1084.              * reset the control information.
  1085.              */
  1086.  
  1087.         if(Buffer -> Read)
  1088.         {
  1089.             Buffer -> WriteBufFull    = Buffer -> BufLength;
  1090.             Buffer -> BufPosition    = 0;
  1091.             Buffer -> Read        = FALSE;
  1092.         }
  1093.  
  1094.             /* Set up for write access. */
  1095.  
  1096.         Buffer -> Written = TRUE;
  1097.  
  1098.         BufPosition    = Buffer -> BufPosition;
  1099.         WriteBufFull    = Buffer -> WriteBufFull;
  1100.         Data        = &Buffer -> Data[BufPosition];
  1101.  
  1102.             /* Remember access. */
  1103.  
  1104.         Buffer -> Used    = TRUE;
  1105.  
  1106.             /* Continue until all data has been processed. */
  1107.  
  1108.         while(Size)
  1109.         {
  1110.                 /* Determine number of bytes to transfer. */
  1111.  
  1112.             if(ToCopy = (Size > WriteBufFull ? WriteBufFull : Size))
  1113.             {
  1114.                 CopyMem(Source,Data,ToCopy);
  1115.  
  1116.                 Size        -= ToCopy;
  1117.                 BufPosition    += ToCopy;
  1118.                 WriteBufFull    -= ToCopy;
  1119.                 Source        += ToCopy;
  1120.                 Data        += ToCopy;
  1121.                 BytesWritten    += ToCopy;
  1122.             }
  1123.             else
  1124.             {
  1125.                     /* Flush the contents of the
  1126.                      * write buffer.
  1127.                      */
  1128.  
  1129.                 Buffer -> BufPosition    = BufPosition;
  1130.                 Buffer -> WriteBufFull    = WriteBufFull;
  1131.  
  1132.                 if(!BufferFlush(Buffer))
  1133.                     return(BytesWritten);
  1134.  
  1135.                     /* Pick up new data. */
  1136.  
  1137.                 BufPosition        = Buffer -> BufPosition;
  1138.                 WriteBufFull        = Buffer -> WriteBufFull;
  1139.                 Data            = Buffer -> Data;
  1140.  
  1141.                     /* Important - or BufferFlush() won't
  1142.                      * write the final buffer contents when
  1143.                      * the buffered file handle is freed up.
  1144.                      */
  1145.  
  1146.                 Buffer -> Written = TRUE;
  1147.             }
  1148.         }
  1149.  
  1150.             /* Install new data. */
  1151.  
  1152.         Buffer -> BufPosition    = BufPosition;
  1153.         Buffer -> WriteBufFull    = WriteBufFull;
  1154.  
  1155.         return(BytesWritten);
  1156.     }
  1157. }
  1158.